package cn._2dland.oauth;

import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import cn._2dland.http.HttpClient;
import cn._2dland.http.method.HttpMethod;
import cn._2dland.util.SignatureAlgorithm;
import cn._2dland.util.SignatureAlgorithmFactory;
import cn._2dland.util.URIEncoder;

public class OAuthClient extends HttpClient {

	/** OAuth参数：应用API Key */
	public static final String OAUTH_CONSUMER_KEY = "oauth_consumer_key";
	/** OAuth参数：访问令牌 */
	public static final String OAUTH_TOKEN = "oauth_token";
	/** OAuth参数：授权码 */
	public static final String OAUTH_VERIFIER = "oauth_verifier";
	/** OAuth参数：时间戳 */
	public static final String OAUTH_TIMESTAMP = "oauth_timestamp";
	/** OAuth参数：随机串 */
	public static final String OAUTH_NONCE = "oauth_nonce";
	/** OAuth参数：签名方法 */
	public static final String OAUTH_SIGNATURE_METHOD = "oauth_signature_method";
	/** OAuth参数：签名 */
	public static final String OAUTH_SIGNATURE = "oauth_signature";

	/** 当前采用的加密算法 */
	private static final String DEFAULT_SIGNATURE_METHOD = SignatureAlgorithmFactory.ALGORITHM_HMAC_SHA1;

	/** 应用标识 */
	private String apiKey = null;
	/** 访问令牌 */
	private String token = null;
	/** 签名密钥 */
	private String signKey = null;

	public OAuthClient(String apiKey, String token, String secret) {
		super();

		this.apiKey = apiKey;
		this.token = token;
		this.signKey = secret;

		super.addHeader("Authorization", "OAuth");
	}

	@Override
	public int executeMethod(HttpMethod method) {
		// 追加OAuth参数
		method.addParameter(OAUTH_CONSUMER_KEY, apiKey);
		method.addParameter(OAUTH_TOKEN, token);
		method.addParameter(OAUTH_SIGNATURE_METHOD, DEFAULT_SIGNATURE_METHOD);
		method.addParameter(OAUTH_TIMESTAMP, getTimestamp());
		method.addParameter(OAUTH_NONCE, getNonce());

		// 对参数进行签名
		String sign = signature(method.getURL(), method.getMethodName(), method.getParameters());
		// 追加参数签名
		method.addParameter(OAUTH_SIGNATURE, sign);

		return super.executeMethod(method);
	}

	/**
	 * 生成时间戳
	 * 
	 * @return
	 */
	private String getTimestamp() {
		long now = System.currentTimeMillis();
		return String.valueOf(now);
	}

	/**
	 * 生成随机串
	 * 
	 * @return
	 */
	private String getNonce() {
		return String.valueOf(Math.random());
	}

	/**
	 * 对HTTP请求进行签名
	 * 
	 * @param url
	 * @param method
	 * @param params
	 * @return
	 */
	private String signature(String url, String method, Map<String, String> params) {
		String sign = null;
		try {
			// 构造Base String
			StringBuffer baseStr = new StringBuffer();
			baseStr.append(method).append("&");
			baseStr.append(URLEncoder.encode(url, "utf-8")).append("&");
			baseStr.append(getParamString(params));

			// 执行签名
			SignatureAlgorithm sa = SignatureAlgorithmFactory.getAlgorithm(DEFAULT_SIGNATURE_METHOD);
			sign = sa.signature(signKey.getBytes(), baseStr.toString().getBytes());
		} catch (Exception e) {
		}

		return sign;
	}

	/**
	 * 将参数排序后，拼成一个字符串
	 * 
	 * @param params
	 * @return
	 */
	private String getParamString(Map<String, String> params) {
		// 对参数名进行排序
		List<String> names = new ArrayList<String>(params.size());
		for(String name : params.keySet()) {
			// 插入排序
			boolean inserted = false;
			for(int i=0; i<names.size(); i++) {
				// 若当前元素小于要插入的元素，跳过
				if(names.get(i).compareTo(name) <= 0)
					continue;

				// 插入元素
				names.add(i, name);
				inserted = true;
				break;
			}
			if(!inserted)
				names.add(name);
		}

		// 构造参数串
		StringBuffer paramBuf = new StringBuffer();
		String sep = "";
		for(int i=0; i<names.size(); i++) {
			String paramName = names.get(i);
			String paramValue = params.get(paramName);

			paramBuf.append(sep).append(paramName).append("%3D").append(URIEncoder.encode(paramValue, "utf-8"));
			sep = "%26";
		}

		return paramBuf.toString();
	}
}
